import pandas as pd
import numpy as np
data = pd.read_csv('../data/heloc_dataset_v1.csv')
data['RiskPerformance'] = np.where(data.RiskPerformance=='Bad',1,0)
data.head(2)
data.shape
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score, accuracy_score, f1_score, precision_score, recall_score
from sklearn.feature_selection import SelectKBest
X_train, X_test, y_train, y_test = \
train_test_split(data.drop('RiskPerformance', axis =1), data.RiskPerformance, test_size=.33, random_state=42)
seletor_f_classif = SelectKBest(k='all')
seletor_f_classif.fit_transform(X_train, y_train)
cols_f_classif = pd.DataFrame({
'column':X_train.columns,
'score': seletor_f_classif.scores_,
'p_value':seletor_f_classif.pvalues_
}).sort_values('score', ascending = False)
column_list = cols_f_classif.query("score>10").column.values
all_columns = np.concatenate((column_list, ['RiskPerformance']))
X_train, X_test, y_train, y_test = \
train_test_split(data[column_list], data.RiskPerformance, test_size=.33, random_state=42)
clf_win = LogisticRegression(
random_state=123,
max_iter = 200,
solver = 'liblinear'
)
clf_win.fit(X_train, y_train)
y_pred = clf_win.predict_proba(X_test)[:,1]
y_pred2 = clf_win.predict(X_test)
print(" AUC = ",round(roc_auc_score( y_test, y_pred)*100,2),
" ACC = ", round(accuracy_score( y_test, y_pred2)*100,2),
" F1 = ", round(f1_score( y_test, y_pred2)*100,2),
" Precision = ", round(precision_score( y_test, y_pred2)*100,2),
" Recall = ", round(recall_score( y_test, y_pred2)*100,2))
from lime import lime_tabular
explainer = lime_tabular.LimeTabularExplainer(
X_train,
feature_names=data[all_columns],
class_names=['0','1'],
discretize_continuous=False
)
y_pred
results = pd.DataFrame({'true':y_test, 'pred':y_pred})
results['diff'] = abs(results.true - results.pred)
results.sort_values('diff').loc[results['true']==0]
Obserwacja, która miała najwyższe prawdopodobieństwo bycia w klasie 1
selected_obs = X_test.loc[7585]
exp = explainer.explain_instance(selected_obs, clf_win.predict_proba, num_features=8, top_labels=1)
exp.show_in_notebook(show_table=True, show_all=False)
Obserwacja, która miała najniższe prawdopodobieństwo bycia w klasie 1 (została zaklasyfikowana jako pewne 0)
selected_obs4 = X_test.loc[6409]
exp4 = explainer.explain_instance(selected_obs4, clf_win.predict_proba, num_features=819, top_labels=1)
exp4.show_in_notebook(show_table=True, show_all=False)
Obserwacja, która miała najniższe prawdopodobieństwo bycia w klasie 0 (Została zaklasyfikowana jako pewne 1)
selected_obs2 = X_test.loc[1039]
exp2 = explainer.explain_instance(selected_obs2, clf_win.predict_proba, num_features=19, top_labels=1)
exp2.show_in_notebook(show_table=True, show_all=False)
Obserwacja, która miała najwyższe prawdopodobieństwo bycia w klasie 0
selected_obs3 = X_test.loc[3785]
exp3 = explainer.explain_instance(selected_obs3, clf_win.predict_proba, num_features=8, top_labels=1)
exp3.show_in_notebook(show_table=True, show_all=False)
Pierwszy wykres to true positive, drugi to false positive.
NumInqLast6M która mówi o ilości zapytań (coś podobnego do BIK) w ciągu ostatnich 6 miesięcy, a więc można przypuszczać, że w ciągu ostatnich 6 miesięcy tyle razy dany klient próbował wziąć kredyt.NumInqLast6Mexcl7days, która mówi o ilości zapytań w ciągu ostatnich 6 miesięcy, ale wyłączając ostatnie 7 dni.
Warto zauważyć, że obie zmienne niosą bardzo podobną informację (w obu tych przypadkach nawet wartości są takie same), ale zmienne te wpływają bardzo pozytywnie bądź bardzo negatywnie. Co przy regresji jest dość ciekawą obserwacją.ExternalRiskEstimate i jest to miara łącząca inne miary mówiące o ryzyku. W obu przypadkach ta wartość jest mniej więcej podobna. Wniosek może być taki, że te miary już są obarczone błędem, przez co nasz model je dubluje.NumSatisfactoryTrades, która mówi o ilości transacji pozytywnie zamkniętych( im mniej tym gorzej), w wypadku oby tych obserwacji, działa to na korzyść klasy "0", co jest sprzeczne z intuicją.NumTrades60EverDerogPubRec, która mówi ile razy kiedykolwiek ktoś się opóźniał w spłacie więcej niż 60 dni. Oczyiwście im więcej tym gorzej. Druga obserwacja 'False Positive' ma tą wartość jako 0. Więc nie ma przełanek aby ten klient był zły, jednak przez nasz model jest to traktowane na korzyść "złej" klasy.print('True Positive')
exp.show_in_notebook(show_table=True, show_all=False)
print('False Positive')
exp2.show_in_notebook(show_table=True, show_all=True)
Pierwsza obserwacja to True Negative, druga False Negative
print('True Negative')
exp3.show_in_notebook(show_table=True, show_all=False)
print('False Negative')
exp4.show_in_notebook(show_table=True, show_all=False)
Spójrzmy na wyjaśnienia tej samej obserwacji, ale num_features z 18 zmienimy na 19 (o jedną więcej zmiennych)
Zauważmy, że od piątej zmiennej "ważność" i kolejność tych zmiennych się zmienia. A przecież dodałam tylko jedną mienną do wyjaśnień..
exp2 = explainer.explain_instance(selected_obs2, clf_win.predict_proba, num_features=18, top_labels=1)
print(' 18 zmiennych')
exp2.show_in_notebook(show_table=True, show_all=False)
exp22 = explainer.explain_instance(selected_obs2, clf_win.predict_proba, num_features=19, top_labels=1)
print(' 19 zmiennych')
exp22.show_in_notebook(show_table=True, show_all=False)
from sklearn.neural_network import MLPClassifier
clf = MLPClassifier(alpha=1, max_iter=1000)
clf.fit(X_train, y_train)
y_pred_nn = clf.predict_proba(X_test)
Weźmy obserwację False Negative. Widać, że zmienne w różnych modelach wskazują na inną klasę, na przykład:
PercentTradesWBalance, która mówi o procencie tranckacji dla regresji logistycznej wskazuje na klasę '1', a dla sieci wskazuje na klasę '0' z mocą 0.04,MaxDelqEver, która mówi o maksymalnym opóźnieniu kiedykolwiek, dla regresji logistycznejwskazuje na klasę '0' z mocą 0.04, a dla sieci wskazuje na klasę '1' z mocą 0.03NetFractionInstallBurden również w zależności od modelu wskazuje na różne klasy, jednak "moc" tej zmiennej jest znikoma.print('Model regresji logistycznej')
exp4.show_in_notebook(show_table=True, show_all=False)
exp_nn = explainer.explain_instance(selected_obs4, clf.predict_proba, num_features=19, top_labels=1)
print('Sieć Neuronowa')
exp_nn.show_in_notebook(show_table=True, show_all=False)